package com.kaisu.blog.infrastructure.utils;

import com.kaisu.blog.infrastructure.annotations.QueryIgnore;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.Objects.nonNull;

/**
 * @author kaisu
 */
public class PredicateUtils {
    public static <T> Predicate getDefaultPagePredicate(Map<String, String> filter,
                                                        Map<String, String> search,
                                                        Root<T> root, CriteriaBuilder criteriaBuilder) {
        Set<String> ignoreColumn = Arrays.stream(root.getJavaType().getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(QueryIgnore.class))
                .map(Field::getName)
                .collect(Collectors.toSet());
        Predicate filterPredicate = criteriaBuilder.and();
        Predicate searchPredicate = criteriaBuilder.and();
        if (nonNull(filter) && !filter.isEmpty()) {
            Set<String> filterKeys = new HashSet<>(filter.keySet());
            filter.keySet().removeAll(ignoreColumn);
            List<Predicate> filterPredicates = filterKeys.stream()
                    .map(key -> criteriaBuilder.equal(root.get(key), filter.get(key)))
                    .toList();
            filterPredicate = criteriaBuilder.and(filterPredicates.toArray(new Predicate[0]));
        }
        if (nonNull(search) && !search.isEmpty()) {
            Set<String> searchKeys = new HashSet<>(search.keySet());
            searchKeys.removeAll(ignoreColumn);
            List<Predicate> searchPredicates = searchKeys.stream()
                    .map(key -> criteriaBuilder.like(root.get(key), "%" + search.get(key) + "%"))
                    .toList();
            searchPredicate = criteriaBuilder.and(searchPredicates.toArray(new Predicate[0]));
        }
        return criteriaBuilder.and(filterPredicate, searchPredicate);
    }
}
